001 /* 002 * Copyright 2005 Stephen J. McConnell 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.tools.tasks; 020 021 import java.io.File; 022 import java.util.ArrayList; 023 import java.util.List; 024 025 import net.dpml.lang.UnknownKeyException; 026 027 import net.dpml.library.Resource; 028 import net.dpml.library.ResourceNotFoundException; 029 import net.dpml.library.Type; 030 import net.dpml.library.info.Scope; 031 032 import net.dpml.transit.Artifact; 033 import net.dpml.transit.Transit; 034 import net.dpml.transit.Layout; 035 036 import org.apache.tools.ant.BuildException; 037 import org.apache.tools.ant.taskdefs.Copy; 038 039 /** 040 * Consolidates a set of resources based on project dependencies. 041 * 042 * @author <a href="http://www.dpml.net">The Digital Product Meta Library</a> 043 * @version 1.0.0 044 */ 045 public class ReplicateTask extends GenericTask 046 { 047 private String m_key; 048 private String m_ref; 049 private File m_todir; 050 private String m_layout; 051 052 private boolean m_verbose = false; 053 private boolean m_self = false; 054 055 private ArrayList m_includes = new ArrayList(); 056 057 /** 058 * Set the key of the target project or resource. 059 * 060 * @param key the resource key 061 */ 062 public void setKey( final String key ) 063 { 064 m_key = key; 065 } 066 067 /** 068 * Set the ref of the target project or resource. 069 * 070 * @param ref the resource reference 071 */ 072 public void setRef( final String ref ) 073 { 074 m_ref = ref; 075 } 076 077 /** 078 * Set the id of the target layout strategy. 079 * 080 * @param id the layout identifier 081 */ 082 public void setLayout( final String id ) 083 { 084 m_layout = id; 085 } 086 087 /** 088 * Set the verbose policy. 089 * @param flag the verbose flag 090 */ 091 public void setVerbose( boolean flag ) 092 { 093 m_verbose = flag; 094 } 095 096 /** 097 * Settting self to TRUE will result in expansion of the path to include 098 * the target resource. 099 * @param flag the self inclusion flag 100 */ 101 public void setSelf( boolean flag ) 102 { 103 m_self = flag; 104 } 105 106 /** 107 * Create and add a new include. 108 * @return the include 109 */ 110 public Include createInclude() 111 { 112 Include include = new Include(); 113 m_includes.add( include ); 114 return include; 115 } 116 117 /** 118 * The target directory to copy cached based path elements to. 119 * @param todir the destination directory 120 */ 121 public void setTodir( File todir ) 122 { 123 m_todir = todir; 124 } 125 126 /** 127 * Execute the task. 128 */ 129 public void execute() 130 { 131 if( null == m_todir ) 132 { 133 File target = getContext().getTargetDirectory(); 134 m_todir = new File( target, "replicate" ); 135 } 136 137 File destination = m_todir; 138 Layout layout = resolveLayout(); 139 ArrayList list = new ArrayList(); 140 String ref = getRef(); 141 if( null != ref ) 142 { 143 Resource resource = getResource( ref ); 144 aggregate( list, resource, m_self ); 145 } 146 147 // 148 // add nested includes 149 // 150 151 Include[] includes = (Include[]) m_includes.toArray( new Include[0] ); 152 for( int i=0; i<includes.length; i++ ) 153 { 154 Include include = includes[i]; 155 String includeRef = include.getRef(); 156 Resource resource = getResource( includeRef ); 157 aggregate( list, resource, true ); 158 } 159 160 // 161 // get sorted list of resources 162 // 163 164 Resource[] resources = (Resource[]) list.toArray( new Resource[0] ); 165 Resource[] selection = getContext().getLibrary().sort( resources ); 166 File cache = (File) getProject().getReference( "dpml.cache" ); 167 for( int i=0; i<selection.length; i++ ) 168 { 169 Resource resource = selection[i]; 170 copy( cache, destination, resource, layout ); 171 } 172 } 173 174 /** 175 * Copy the artifacts produced by the Resource from the cache to 176 * the destination using a suppplied target layout. 177 */ 178 private void copy( File cache, File destination, Resource resource, Layout layout ) 179 { 180 Type[] types = resource.getTypes(); 181 for( int j=0; j<types.length; j++ ) 182 { 183 Type type = types[j]; 184 String id = type.getID(); 185 186 Artifact artifact = resource.getArtifact( id ); 187 copyArtifact( artifact, cache, destination, layout ); 188 if( null != type.getVersion() ) 189 { 190 Artifact link = resource.getLinkArtifact( id ); 191 copyArtifact( link, cache, destination, layout ); 192 } 193 } 194 } 195 196 private void copyArtifact( Artifact artifact, File cache, File destination, Layout layout ) 197 { 198 String sourcePath = Transit.getInstance().getCacheLayout().resolvePath( artifact ); 199 File source = new File( cache, sourcePath ); 200 if( !source.exists() ) 201 { 202 final String error = 203 "Cached resource [" 204 + source 205 + "] does not exist."; 206 log( error ); 207 } 208 else 209 { 210 String destPath = layout.resolvePath( artifact ); 211 File dest = new File( destination, destPath ); 212 copyFile( source, dest ); 213 File md5 = new File( cache, sourcePath + ".md5" ); 214 if( md5.exists() ) 215 { 216 copyFile( md5, new File( destination, destPath + ".md5" ) ); 217 } 218 File asc = new File( cache, sourcePath + ".asc" ); 219 if( asc.exists() ) 220 { 221 copyFile( asc, new File( destination, destPath + ".asc" ) ); 222 } 223 } 224 } 225 226 private void copyFile( File source, File dest ) 227 { 228 dest.getParentFile().mkdir(); 229 final Copy copy = (Copy) getProject().createTask( "copy" ); 230 copy.setFile( source ); 231 copy.setTofile( dest ); 232 copy.setPreserveLastModified( true ); 233 copy.setVerbose( m_verbose ); 234 copy.init(); 235 copy.execute(); 236 } 237 238 private Layout resolveLayout() 239 { 240 if( null == m_layout ) 241 { 242 return Transit.getInstance().getCacheLayout(); 243 } 244 else 245 { 246 try 247 { 248 return Transit.getInstance().getLayout( m_layout ); 249 } 250 catch( UnknownKeyException e ) 251 { 252 final String error = 253 "Target layout id [" 254 + m_layout 255 + "] is unknown."; 256 throw new BuildException( error, e, getLocation() ); 257 } 258 catch( Exception e ) 259 { 260 final String error = 261 "Unexpected error while resolving layout: " + m_layout; 262 throw new BuildException( error, e, getLocation() ); 263 } 264 } 265 } 266 267 private void aggregate( List list, Resource resource, boolean self ) 268 { 269 Resource[] resources = resource.getAggregatedProviders( Scope.RUNTIME, true, false ); 270 for( int i=0; i<resources.length; i++ ) 271 { 272 Resource r = resources[i]; 273 if( !list.contains( r ) ) 274 { 275 list.add( r ); 276 } 277 } 278 if( self ) 279 { 280 if( !list.contains( resource ) ) 281 { 282 list.add( resource ); 283 } 284 } 285 } 286 287 private Resource[] getPathResources( Resource resource ) 288 { 289 Resource[] resources = resource.getAggregatedProviders( Scope.RUNTIME, true, false ); 290 if( m_self ) 291 { 292 Resource[] result = new Resource[ resources.length + 1 ]; 293 System.arraycopy( resources, 0, result, 0, resources.length ); 294 result[ resources.length ] = resource; 295 return result; 296 } 297 else 298 { 299 return resources; 300 } 301 } 302 303 304 private String getRef() 305 { 306 if( null != m_ref ) 307 { 308 return m_ref; 309 } 310 else if( null != m_key ) 311 { 312 return getResource().getParent().getResourcePath() + "/" + m_key; 313 } 314 else 315 { 316 return getResource().getResourcePath(); 317 } 318 } 319 320 private Resource getResource( String ref ) 321 { 322 try 323 { 324 return getContext().getLibrary().getResource( ref ); 325 } 326 catch( ResourceNotFoundException e ) 327 { 328 final String error = 329 "Feature reference [" 330 + ref 331 + "] in the project [" 332 + getResource() 333 + "] is unknown."; 334 throw new BuildException( error, e ); 335 } 336 } 337 338 /** 339 * Declaration of an include. 340 */ 341 public class Include 342 { 343 private String m_includekey; 344 private String m_includeRef; 345 346 /** 347 * Set the key of the target project or resource. 348 * 349 * @param key the resource key 350 */ 351 public void setKey( final String key ) 352 { 353 m_includekey = key; 354 } 355 356 /** 357 * Set the ref of the target project or resource. 358 * 359 * @param ref the resource reference 360 */ 361 public void setRef( final String ref ) 362 { 363 m_includeRef = ref; 364 } 365 366 private String getRef() 367 { 368 if( null != m_includeRef ) 369 { 370 return m_includeRef; 371 } 372 else if( null != m_includekey ) 373 { 374 return getResource().getParent().getResourcePath() + "/" + m_includekey; 375 } 376 else 377 { 378 final String error = 379 "Missing 'ref' or 'key' attribute."; 380 throw new BuildException( error, getLocation() ); 381 } 382 } 383 } 384 }